#include "dx8_graphics.h"
#include <dxerr8.h>
#include <winuser.h>

//#include "dx8_fontx.h"
#include "dx8_font.h"
#include "dx8_image_cache.h"
#include "dx8_buffer.h"

#include "gameswf/gameswf.h"

#include "dx8_surface.h"
#include "dx8_dynamic_image.h"
#include "dx8_avi.h"

#include "application/game_application.h"

#include "util/timer.h"				// log
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    

#include <cassert>


extern GameApp*	g_pApp;

Dx8Graphics*	GetDXGraphics()
{
	return (Dx8Graphics*)GetGraphics();
}	

void		Dx8Graphics::Create()
{
	assert(!s_pGraphics && "Unable to create graphics! Already initialized!");
	if (!s_pGraphics)
	{
		s_pGraphics = new Dx8Graphics();
		// force images to register
		Dx8Surface::RegisterFormats();
	}
}

void		SLEIPNER_CREATE_DX8()
{
	Dx8Graphics::Create();
}

void*		Dx8Graphics::GetFlashDriver()
{
	return gameswf::create_render_handler_d3d(m_pd3dDevice);
}


ImageCache*		Dx8Graphics::CreateCache(int Width, int Height, int Depth)
{
//	assert(0 && "Should return a cache!");

	ImageCache* pCache = new DX8ImageCache();
	pCache->Create(Width, Height, Depth);
	return pCache;	
}


void		Dx8Graphics::Delete()
{
	assert(s_pGraphics && "Unable to delete graphics! Not yet initialized!");
	UTIL_SAFE_DELETE(s_pGraphics);
}


Dx8Graphics::Dx8Graphics() : 
	Graphics(),
	m_pD3D(0),
	m_pd3dDevice(0),
	m_ProcessMode(VP_MIXED),
	m_InvalidState(true),
	m_WindowHandle(0)
{
	memset(&m_d3ddm, 0, sizeof(m_d3ddm));
	memset(&m_d3d8Caps, 0, sizeof(m_d3d8Caps));

	for (int i=0; i<BUG_COUNT; i++)
		m_BugList[i] = false;

	m_DeviceID = D3DADAPTER_DEFAULT;
}

Dx8Graphics::~Dx8Graphics()
{
	FlushBuffers();
}

void Dx8Graphics::FlushBuffers()
{
	for (unsigned int i=0; i<m_VBSets.size(); i++)
	{
		delete m_VBSets[i];
	}
	m_VBSets.resize(0);
	for (unsigned int i=0; i<m_IBSets.size(); i++)
	{
		delete m_IBSets[i];
	}
	m_IBSets.resize(0);
}

void	Dx8Graphics::BuildPresentationParams(unsigned int Width, unsigned int Height, bool Fullscreen)
{
	HRESULT hRes;
    if( FAILED( m_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &m_d3ddm) ) )
	{
		return ;
	}

	assert(m_pD3D && "Not initialized D3D Yet!");
    ZeroMemory( &m_d3dpp, sizeof(m_d3dpp) );
	m_IsWindowed					 = !Fullscreen;

	if ((!g_pApp->GetHandler()->IsWidescreen() || g_pApp->GetHandler()->IsNativeWidescreen()) && Fullscreen)
	{
		m_d3dpp.Windowed = FALSE;
		m_d3dpp.Flags = 0;
		m_d3dpp.hDeviceWindow = m_WindowHandle;
		m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // PIERRE: D3DSWAPEFFECT_FLIP
		m_d3dpp.BackBufferCount = 1; // PIERRE: 2
		m_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
		m_d3dpp.BackBufferWidth = Width;
		m_d3dpp.BackBufferHeight = Height;
		m_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
		if (m_BugList[BUG_16BIT_ONLY])
		{
			m_d3dpp.BackBufferFormat		 = D3DFMT_R5G6B5;
		}
		m_d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
		m_d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
		 
       
		hRes = m_pD3D->CheckDeviceFormat( 
				m_DeviceID, D3DDEVTYPE_HAL,
				m_d3dpp.BackBufferFormat, 
				D3DUSAGE_RENDERTARGET,
				D3DRTYPE_SURFACE, 
				m_d3dpp.BackBufferFormat);
		if (FAILED(hRes))
		{
			_LOG(MSG_FATAL, "Error testing device format for fullscreen!");
            _LOG(MSG_FATAL, "DX Error: " << GetDXError(hRes));
		}
	} else
	{
		m_d3dpp.BackBufferWidth			 = Width;
		m_d3dpp.BackBufferHeight		 = Height;
		m_d3dpp.BackBufferFormat		 = D3DFMT_X8R8G8B8;

		if (m_BugList[BUG_16BIT_ONLY])
		{
			m_d3dpp.BackBufferFormat		 = D3DFMT_R5G6B5;
		}

		m_d3dpp.hDeviceWindow = m_WindowHandle;
		m_d3dpp.Windowed = TRUE;
		m_d3dpp.SwapEffect = /*Fullscreen ? D3DSWAPEFFECT_COPY_VSYNC : */D3DSWAPEFFECT_DISCARD;	// PIERRE: FULLSCREEN
		m_d3dpp.EnableAutoDepthStencil = FALSE;
		m_d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
		m_d3dpp.BackBufferCount = 1; // PIERRE: 2
		m_d3dpp.Flags = 0;
		m_d3dpp.EnableAutoDepthStencil = false;
		m_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;

		m_d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

	}



}


void	Dx8Graphics::SetupWindow(unsigned int Width, unsigned int Height, bool Fullscreen, bool Init)
{
	bool HasFocus = g_pApp->GetHandler()->HasFocus();
	if (Fullscreen)
	{
		_LOG(MSG_COMMENT, "Setting up fullscreen parameters");

		// messed up
		if (g_pApp->GetHandler()->IsWidescreen() && !g_pApp->GetHandler()->IsNativeWidescreen())
		{
			unsigned int ScreenX, ScreenY;
			GetBestWideScreenRes(ScreenX, ScreenY, false);
			if (g_pApp->GetHandler()->SetResolution(ScreenX, ScreenY, g_pApp->GetHandler()->GetOrigDepth()))
			{
				Width = ScreenX;
				Height = ScreenY;
			}
			else
			{
				// failed... revert to current screen res
				Width = GetSystemMetrics(SM_CXSCREEN);
				Height = GetSystemMetrics(SM_CYSCREEN);
			}
		}

		// ADRIAN: reset windowed position when toggling full screen
		UINT Flags = SWP_FRAMECHANGED;
		m_WindowX = m_WindowY = -1;

		if (!Init && !HasFocus)
			Flags |= SWP_NOACTIVATE;

	    ::SetWindowLong(m_WindowHandle, GWL_STYLE, WS_POPUP);
		::SetWindowLong(m_WindowHandle, GWL_EXSTYLE, WS_EX_APPWINDOW );
		::SetWindowPos(	m_WindowHandle, 
						HWND_TOP,
						///(g_bWidescreen ||m_BugList[BUG_VISTA_ALTTAB])?HWND_TOP:HWND_TOPMOST,
						0, 0, 
						Width,
						Height,
						Flags);
	} else
	{
		_LOG(MSG_COMMENT, "Setting up windowed parameters");

		if (g_pApp->GetHandler()->IsWidescreen() && !g_pApp->GetHandler()->IsNativeWidescreen())
		{
			// restore desktop res before doing anything else
			_LOG(MSG_COMMENT, "Resolution was changed. Restoring...");
			g_pApp->GetHandler()->RestoreResolution();
		}

		// resize window before we create the bastard thing
		unsigned int Caption = GetSystemMetrics(SM_CYCAPTION);
		unsigned int BorderX = GetSystemMetrics(SM_CXBORDER);
		unsigned int BorderY = GetSystemMetrics(SM_CYBORDER);
		unsigned int ScreenX = GetSystemMetrics(SM_CXSCREEN); //get current resolution X
		unsigned int ScreenY = GetSystemMetrics(SM_CYSCREEN); //get current resolution Y
		unsigned int DialogX = GetSystemMetrics(SM_CXDLGFRAME);
		unsigned int DialogY = GetSystemMetrics(SM_CYDLGFRAME);


		DEVMODE device_mode;
		memset(&device_mode, 0, sizeof(DEVMODE));
		device_mode.dmSize = sizeof(DEVMODE);
		EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &device_mode);

		int ScreenWidth = device_mode.dmPelsWidth;
		int ScreenHeight = device_mode.dmPelsHeight;

		// PIERRE: FULLSCREEN
		int	WindowW		= Width + (BorderX*2) + (DialogX*2);
		int	WindowH		= Height + Caption + (BorderY*2) + (DialogY*2);
		long Res = ::SetWindowLong(m_WindowHandle, GWL_STYLE, WS_CLIPCHILDREN | WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
		if (!Res) _LOG(MSG_ERROR, "Unable to setup draw style : !" << GetLastError());
			
		Res = ::SetWindowLong(m_WindowHandle, GWL_EXSTYLE,WS_EX_APPWINDOW | WS_EX_WINDOWEDGE|WS_EX_ACCEPTFILES);
		if (!Res) _LOG(MSG_ERROR, "Unable to setup drawex style : !" << GetLastError());

		// ADRIAN: retain previous window position
		DWORD dwWindowPosFlag = SWP_NOMOVE;
		if ((m_WindowX < 0)	|| (m_WindowY < 0))
		{
			m_WindowX = (ScreenWidth - WindowW)/2;
			m_WindowY = (ScreenHeight - WindowH)/2;
			dwWindowPosFlag = 0;
		}
		if (!HasFocus && !Init)
			dwWindowPosFlag |= SWP_NOACTIVATE;

		Res = ::SetWindowPos(	m_WindowHandle, 
						HWND_NOTOPMOST,
						m_WindowX, m_WindowY, 
						WindowW, WindowH,
						SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_FRAMECHANGED | dwWindowPosFlag );	

		if (!Res) _LOG(MSG_ERROR, "Unable to setup window position :" << GetLastError());

		//ALEXANDER: a fix of window size
		RECT CurWinRect;
		RECT CurClientRect;

		GetWindowRect(m_WindowHandle, &CurWinRect);
		GetClientRect(m_WindowHandle, &CurClientRect);

		CurWinRect.right  += Width - (CurClientRect.right - CurClientRect.left);
		CurWinRect.bottom += Height- (CurClientRect.bottom- CurClientRect.top );
		
		int NewWindowedWidth = CurWinRect.right - CurWinRect.left;
		int NewWindowedHeight= CurWinRect.bottom - CurWinRect.top;

		//setting new fixed coords
		UINT swpFlags = SWP_NOMOVE;
		if (!HasFocus && !Init)
			swpFlags |= SWP_NOACTIVATE;
		Res = ::SetWindowPos(m_WindowHandle, HWND_NOTOPMOST, CurWinRect.left, CurWinRect.top,
								NewWindowedWidth, 
								NewWindowedHeight, swpFlags );

		if (!Res) _LOG(MSG_ERROR, "Unable to setup tweaked window position :" << GetLastError());

	}

	if (HasFocus || Init)
		::ShowWindow(m_WindowHandle, SW_SHOW);
	
}

bool	Dx8Graphics::ResetWindow(unsigned int Width, unsigned int Height, bool Fullscreen)
{
	// FIXME: Collapse this to avoid this massive copy-paste
	HRESULT hRes;
	m_IsWindowed					 = !Fullscreen;
	BuildPresentationParams(Width, Height, Fullscreen);

	Sleep(100);

	hRes = m_pd3dDevice->Reset(&m_d3dpp);
	if (FAILED(hRes))
    {
		_LOG(MSG_WARNING, "Unable to reset 3D Device.. try with delay [" << GetDXError(hRes) << "]");
		int	MaxCount = 20;
		m_InvalidState = true;
		while (m_InvalidState && MaxCount > 0)
		{
			MaxCount --;
			Sleep(50);
			hRes = m_pd3dDevice->TestCooperativeLevel();
			if (hRes == D3DERR_DEVICENOTRESET)
			{
		        _LOG(MSG_WARNING, "Trying to re-initialize driver");
				hRes = m_pd3dDevice->Reset(&m_d3dpp);
				if (FAILED(hRes))
				{
					_LOG(MSG_WARNING, "		Failed to reinialize driver!");
				} else
				{
					m_InvalidState = false;
					_LOG(MSG_WARNING, "		Driver successfully initalized!");
				}
			} else
			{
				_LOG(MSG_WARNING, "		Device reset!");
				m_InvalidState = false;
			}
			//g_pApp->ProcessEvents();
		}
    }

	if (!m_InvalidState)
	{
		SetupViewport(Width, Height);
		SetupWindow(Width, Height, Fullscreen, false);
		Resize(g_pApp->GetHandler()->ScreenWidth(), g_pApp->GetHandler()->ScreenHeight());
	}

	return !m_InvalidState;
}

void	Dx8Graphics::SetupViewport(int Width, int Height)
{
	if (m_IsWindowed)
	{
		unsigned int Caption = GetSystemMetrics(SM_CYCAPTION);
		unsigned int BorderX = GetSystemMetrics(SM_CXBORDER);
		unsigned int BorderY = GetSystemMetrics(SM_CYBORDER);
		unsigned int ScreenX = GetSystemMetrics(SM_CXSCREEN); //get current resolution X
		unsigned int ScreenY = GetSystemMetrics(SM_CYSCREEN); //get current resolution Y
		unsigned int DialogX = GetSystemMetrics(SM_CXDLGFRAME);
		unsigned int DialogY = GetSystemMetrics(SM_CYDLGFRAME);

		RECT    WindowSize;
		GetWindowRect(m_WindowHandle, &WindowSize);
		Resize(g_pApp->GetHandler()->ScreenWidth(), g_pApp->GetHandler()->ScreenHeight());
	} else
	{
		Resize(g_pApp->GetHandler()->ScreenWidth(), g_pApp->GetHandler()->ScreenHeight());
	}
}

bool	Dx8Graphics::InitWindow(unsigned int Width, unsigned int Height, bool Fullscreen, bool EnableDebug)
{
	HRESULT hRes;
	assert(m_pD3D && "Not initialized D3D Yet!");

	m_IsWindowed					 = !Fullscreen;
	BuildPresentationParams(Width, Height, Fullscreen);


	m_pd3dDevice = NULL;

    /// Create a Reference rasterize d3d device.. this allows you to do debugging
    /// (step through / break-point) of HLSL shaders. Unfortunatly, this 
    /// will reduce the framerate of your game to <1 fps, so use only 
    /// when debugging specific shader problems.
    if (EnableDebug)
    {
        _LOG(MSG_COMMENT, "Trying to initialize Reference Rasterizer");
		if ( FAILED( hRes = m_pD3D->CreateDevice( m_DeviceID, 
											D3DDEVTYPE_REF,
											m_WindowHandle,		// Create in current window
											D3DCREATE_SOFTWARE_VERTEXPROCESSING,
											&m_d3dpp, 
                                            &m_pd3dDevice ) ) )
        {
		    _LOG(MSG_FATAL, "Unable to create 3D Device");
		    _LOG(MSG_FATAL, "Are you trying to create an unsupported mode ?");
            _LOG(MSG_FATAL, "DX Error: " << GetDXError(hRes));
		    // Critical failure; not able to start creating DX
		    return false;
        }
        _LOG(MSG_INIT, "Initialized Reference Rasterizer!");
		m_ProcessMode = VP_SOFTWARE_ONLY;
    } else
    /// Create the Direct3D device. Here we are using the default adapter (most
    /// systems only have one, unless they have multiple graphics hardware cards
    /// installed) and requesting the HAL (which is saying we want the hardware
    /// device rather than a software one). 
	
	if (m_d3d8Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
	{
		_LOG(MSG_COMMENT, "Trying to initialize full HWTL card");
		hRes = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, 
									 D3DDEVTYPE_HAL, 
			 						 m_WindowHandle,		// Create in current window
									 D3DCREATE_HARDWARE_VERTEXPROCESSING,
									 &m_d3dpp, &m_pd3dDevice );

		if (FAILED(hRes))
		{
			_LOG(MSG_COMMENT, "Trying to initialize mixed-mode HWTL card");
			if( FAILED( hRes = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, 
											 		D3DDEVTYPE_HAL, 
			 										m_WindowHandle,		// Create in current window
													D3DCREATE_MIXED_VERTEXPROCESSING,
													&m_d3dpp, &m_pd3dDevice ) ) )
			{
				m_pd3dDevice = NULL;
				_LOG(MSG_FATAL, "Unable to create 3D Device");
				_LOG(MSG_FATAL, "Are you trying to create an unsupported mode ?");
				_LOG(MSG_FATAL, "DX Error: " << GetDXError(hRes));
			} else
			{
				m_ProcessMode = VP_MIXED;
				_LOG(MSG_INIT, "Initialized D3D HWTL!");
			}
		}
		else
		{
			m_ProcessMode = VP_HW_ONLY;
			_LOG(MSG_INIT, "Initialized D3D HWTL!");
		}
    } 

	// could have gotten lied to by the gfx card
	if (!m_pd3dDevice)
    // Try for software rasterizer..
    {
            _LOG(MSG_COMMENT, "Trying to initialize software T&L card");
			if( FAILED( hRes = m_pD3D->CreateDevice( m_DeviceID, D3DDEVTYPE_HAL, 
											m_WindowHandle,		// Create in current window
											D3DCREATE_SOFTWARE_VERTEXPROCESSING,
											&m_d3dpp, &m_pd3dDevice ) ) )
            {
		        _LOG(MSG_FATAL, "Unable to create 3D Device");
		        _LOG(MSG_FATAL, "Are you trying to create an unsupported mode ?");
                _LOG(MSG_FATAL, "DX Error: " << GetDXError(hRes));
		        // Critical failure; not able to start creating DX
		        return false;
            }
		m_ProcessMode = VP_SOFTWARE_ONLY;
        _LOG(MSG_INIT, "Initialized D3D Software T&L!");
		m_BugList[BUG_SOFTWARE_PROCESSING] = true;
    }
	if (!m_pd3dDevice)	return false;

	_LOG(MSG_INIT, "Init successful with size " << Width << " x " << Height << (Fullscreen ? " fullscreen!" : " windowed!"));

	SetupWindow(Width, Height, Fullscreen, true);
	SetupViewport(Width, Height);
	ShowWindow(m_WindowHandle, SW_SHOW);
	Resize(g_pApp->GetHandler()->ScreenWidth(), g_pApp->GetHandler()->ScreenHeight());
	m_InvalidState = false;

	_LOG(MSG_INIT, "Initialized image loading code!");
	Dx8Surface::RegisterFormats();

	// ADRIAN: try a short sleep to allow driver to... i dunno, init stuff?
	if (Fullscreen) Sleep(100);

	if (BeginScene())
	{
		m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0, 0, 0);
		m_pd3dDevice->EndScene();
	}
	else
	{
		// ADRIAN: full-wide-screen display change may cause this to fail; try to reset
		BuildPresentationParams(Width, Height, Fullscreen);

		// ADRIAN: okay, something's fishy, getting device lost on Luna's PC... let's try resetting multiple times
		bool bReset = false;
		int TryResetC = 10;
		while (!bReset && (TryResetC-- >= 0))
		{
			Sleep(100);
			_LOG(MSG_INIT, "First BeginScene failed, try Resetting...");
			bReset = SUCCEEDED(m_pd3dDevice->Reset(&m_d3dpp));
		}
		//if (SUCCEEDED(m_pd3dDevice->Reset(&m_d3dpp)))
		if (bReset)
		{
			if (BeginScene())
			{
				m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0, 0, 0);
				m_pd3dDevice->EndScene();
			}
		}
		else
		{
			_LOG(MSG_FATAL, "Failed to init after resetting device!");
			return false;
		}
	}
	return true;
}

bool	Dx8Graphics::Init()
{
	_LOG(MSG_INIT, "Initializing D3D8");
    HRESULT hRes = S_OK;;

    // Create D3D Object
	m_pD3D = Direct3DCreate8( D3D_SDK_VERSION );
	if (!m_pD3D)	// NULL if unable to create
	{
		_LOG(MSG_FATAL, "Unable to co-initialise D3D.. ");
		_LOG(MSG_FATAL, "Unable to start DX8.. .is it installed ?");
		// Critical failure; not able to start creating DX
		return false;
	}
	_LOG(MSG_INIT, "D3D8 COM Object created");

    InitCaps(); // go see what the hardware is capable of

//	unsigned int	Mode32C = m_pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_R8G8B8);


	_LOG(MSG_INIT, "D3D8 Initialized successfully");

    return true;

}

bool	Dx8Graphics::ShutdownWindow()
{
	UTIL_SAFE_RELEASE( m_pd3dDevice );
	return true;
}


bool	Dx8Graphics::Shutdown()
{
	ShutdownWindow();
    UTIL_SAFE_RELEASE( m_pD3D );
	return true;
}

bool	Dx8Graphics::Resize(unsigned int Width, unsigned int Height)
{
	return Graphics::Resize(Width, Height);
}


void Dx8Graphics::FlushScreenshot()
{
	if (m_ScreenshotFile.empty()) return;

	assert(m_pd3dDevice);
	IDirect3DSurface8* pBuffer; 

	HRESULT hr = m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBuffer);

	//error checking
	if(FAILED(hr))
	{
		_LOG(MSG_WARNING, "Unable to take screenshot");
        _LOG(MSG_WARNING, "DX Error: " << GetDXError(hr));
		pBuffer->Release(); //release the surface so there is no memory leak
		return;
	}

	std::string	Filename = m_ScreenshotFile+".bmp";
	_LOG(MSG_COMMENT, "Saving screenshot at " << Filename);
	if (m_ScreenshotMinimize)
	{
		D3DSURFACE_DESC		Desc;
		IDirect3DSurface8*	pTarget; 

		pBuffer->GetDesc(&Desc);
		 hr=m_pd3dDevice->CreateImageSurface(Desc.Width/2,Desc.Height/2, Desc.Format, &pTarget);
//		hr=m_pd3dDevice->CreateOffscreenPlainSurface(Desc.Width/2,Desc.Height/2, Desc.Format, D3DPOOL_SYSTEMMEM, &pTarget, NULL);
		if (pTarget)
		{
			hr=D3DXLoadSurfaceFromSurface(	pTarget, NULL, NULL,
										pBuffer, NULL, NULL, D3DX_FILTER_BOX,
										0xFFFFFFFF);
			D3DXSaveSurfaceToFileA(Filename.c_str(), D3DXIFF_BMP, pTarget, NULL, NULL);

			pTarget->Release();
		}
	} else
	{
		D3DXSaveSurfaceToFile(Filename.c_str(), D3DXIFF_BMP, pBuffer, NULL, NULL);
	}
	pBuffer->Release(); //release the surface so there is no memory leak
	m_ScreenshotFile = "";
}

void	Dx8Graphics::SetTexStage(unsigned int TexStage, STAGE_TYPE type, BLEND_OP Op)
{
	if (TexStage < 2)
	{
		assert(type <= Graphics::STAGE_TYPE_COUNT);

		if (m_CurTextureStates[TexStage][type] == Op)
			return;

		m_CurTextureStates[TexStage][type] = Op;
	}

	D3DTEXTURESTAGESTATETYPE	tss;
	unsigned int				tso;
	switch (type)
	{
		case COLOR_ARG1:	tss = D3DTSS_COLORARG1; break;
		case COLOR_ARG2:	tss = D3DTSS_COLORARG2; break;
		case ALPHA_ARG1:	tss = D3DTSS_ALPHAARG1; break;
		case ALPHA_ARG2:	tss = D3DTSS_ALPHAARG2; break;
		case COLOR_OP:		tss = D3DTSS_COLOROP; break;
		case ALPHA_OP:		tss = D3DTSS_ALPHAOP; break;
		case MIP_FILTER:    tss = D3DTSS_MIPFILTER; break;
		default:			tss = D3DTSS_COLOROP;
	}
	switch (Op)
	{
		case BLEND_MODULATE:	tso  = D3DTOP_MODULATE; break;
		case BLEND_ADD:			tso  = D3DTOP_ADD; break;
		case BLEND_SELECTARG1:	tso  = 	D3DTOP_SELECTARG1; break;
		case BLEND_SELECTARG2:	tso  = 	D3DTOP_SELECTARG2; break;
		case BLEND_DISABLE:		tso  = 	D3DTOP_DISABLE; break;

		case SV_DIFFUSE:		tso  = 	D3DTA_DIFFUSE; break;
		case SV_CURRENT:		tso  = 	D3DTA_CURRENT; break;
		case SV_TEXTURE:		tso  = 	D3DTA_TEXTURE; break;
		case SV_CONSTANT:		tso  = 	D3DTA_TFACTOR; break;

		case TEX_LINEAR:		tso  =  D3DTEXF_LINEAR; break;

		case TEX_NONE:			tso  =  D3DTEXF_NONE;  break;

		default:				tso  = 	D3DTOP_MODULATE; 
	}

	assert(m_pd3dDevice && "Invalid device!");
    HRESULT hRes = m_pd3dDevice->SetTextureStageState( TexStage, tss,   tso);
	if (FAILED(hRes))
	{
		_LOG(MSG_WARNING, "Unable to set texture stage because " << GetDXError(hRes));
	}
}

void	Dx8Graphics::SetTexture(unsigned int Stage, Image* pImg) 
{
	if (Stage < 2)
	{
		//if (m_pCurTexture[Stage] == pImg)
		//	return;
	}

	if (pImg)
		pImg->SetTextureStage(Stage);
	else
	{	// disable texture
		m_pd3dDevice->SetTexture(Stage, NULL);
	}

	if (Stage < 2)
		m_pCurTexture[Stage] = pImg;
}



void	Dx8Graphics::SetRenderState(RENDER_STATE r, unsigned int val)
{
	assert (r <= Graphics::RENDER_STATE_C);

	if (m_CurRenderStates[r] == val)
		return;
	else
		m_CurRenderStates[r] = val;

	assert(m_pd3dDevice && "Invalid device!");
	switch (r)
	{
		case RS_ALPHA:
			m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, val);
			break;
		case RS_ALPHA_TEST:
			m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, val);
			break;
		case RS_ALPHA_REF:
			m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, val);
			break;
		case RS_LIGHTING:
			m_pd3dDevice->SetRenderState(D3DRS_LIGHTING, val);
			break;
		case RS_ZWRITE:
			m_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, val);
			break;
		case RS_ZREAD:
			m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, val);
			break;
		case RS_SRC_BLEND:
			{
				int	Value = D3DBLEND_SRCALPHA;
				switch (val)
				{
					case RV_BLEND_ONE: Value = D3DBLEND_ONE; break;
					case RV_BLEND_ZERO: Value = D3DBLEND_ZERO; break;
					case RV_BLEND_SRC: Value = D3DBLEND_SRCCOLOR; break;
					case RV_BLEND_INVSRC: Value = D3DBLEND_INVSRCCOLOR; break;
					case RV_BLEND_SRC_ALPHA: Value = D3DBLEND_SRCALPHA; break;
					case RV_BLEND_INVSRC_ALPHA: Value = D3DBLEND_INVSRCALPHA; break;
					case RV_BLEND_DEST: Value = D3DBLEND_DESTCOLOR; break;
					case RV_BLEND_INVDEST: Value = D3DBLEND_INVDESTCOLOR; break;
					case RV_BLEND_DEST_ALPHA: Value = D3DBLEND_DESTALPHA; break;
					case RV_BLEND_INVDEST_ALPHA: Value = D3DBLEND_INVDESTALPHA; break;
				}
				m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, Value);
			}
			break;
		case RS_DST_BLEND:
			{
				int	Value = D3DBLEND_SRCALPHA;
				switch (val)
				{
					case RV_BLEND_ONE: Value = D3DBLEND_ONE; break;
					case RV_BLEND_ZERO: Value = D3DBLEND_ZERO; break;
					case RV_BLEND_SRC: Value = D3DBLEND_SRCCOLOR; break;
					case RV_BLEND_INVSRC: Value = D3DBLEND_INVSRCCOLOR; break;
					case RV_BLEND_SRC_ALPHA: Value = D3DBLEND_SRCALPHA; break;
					case RV_BLEND_INVSRC_ALPHA: Value = D3DBLEND_INVSRCALPHA; break;
					case RV_BLEND_DEST: Value = D3DBLEND_DESTCOLOR; break;
					case RV_BLEND_INVDEST: Value = D3DBLEND_INVDESTCOLOR; break;
					case RV_BLEND_DEST_ALPHA: Value = D3DBLEND_DESTALPHA; break;
					case RV_BLEND_INVDEST_ALPHA: Value = D3DBLEND_INVDESTALPHA; break;
				}
				m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, Value);
			}break;
		case RS_CULL_MODE:
			{
				switch (val)
				{
				case RV_CULL_NONE:	m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); break;
				case RV_CULL_CW:	m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); break;
				
				case RV_CULL_CCW: 
					default:		m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); break;
				}
			
			}
			break;
	}
}


void	Dx8Graphics::SetTransform(TRANSFORM_STAGE ts, const math::Mat4x4& mat)
{
	D3DTRANSFORMSTATETYPE TransState;
	switch (ts)
	{
		case TS_WORLD:	TransState =					D3DTS_WORLD;	break;
		case TS_VIEW:	TransState =					D3DTS_VIEW;		break;
		case TS_PROJECTION:	TransState =				D3DTS_PROJECTION; break;
		case TS_TEX0:	TransState =					D3DTS_TEXTURE0  ; break;
		case TS_TEX1:	TransState =					D3DTS_TEXTURE1  ; break;
		case TS_TEX2:	TransState =					D3DTS_TEXTURE2  ; break;
		case TS_TEX3:	TransState =					D3DTS_TEXTURE3  ; break;
		case TS_TEX4:	TransState =					D3DTS_TEXTURE4  ; break;
		case TS_TEX5:	TransState =					D3DTS_TEXTURE5  ; break;
		case TS_TEX6:	TransState =					D3DTS_TEXTURE6  ; break;
		case TS_TEX7:	TransState =					D3DTS_TEXTURE7  ; break;
		default:
			TransState =	D3DTS_VIEW; break;
	}
	assert(m_pd3dDevice && "Invalid device!");
	m_pd3dDevice ->SetTransform(TransState, (D3DMATRIX*)&mat);
}

void	Dx8Graphics::SetViewport(const math::Viewport& vp)
{
	if (m_InvalidState) return;
	assert(m_pd3dDevice && "Invalid device!");
    HRESULT hRes = m_pd3dDevice ->SetViewport((D3DVIEWPORT8*)&vp);
    assert(SUCCEEDED(hRes) && "Failed to set viewport for Camera");
}

bool	Dx8Graphics::BeginScene()
{
	// reset our debug counters here
	m_PolygonC= 0;
	m_BatchC=0;
	if (m_InvalidState)
	{
		ResetWindow(m_ScreenWidth, m_ScreenHeight, !m_IsWindowed);
		return false;
	} else
	{
		HRESULT hr = m_pd3dDevice->TestCooperativeLevel();
		if (SUCCEEDED(hr))
		{
			math::Viewport vp;
			vp.X = 0;
			vp.Y = 0;
			if (m_IsWindowed)
			{
				s_PixelOffsetX = s_PixelOffsetY = 0;
			} else
			{	
				GetOriginalPixelOffset(s_PixelOffsetX, s_PixelOffsetY);
			}
			vp.Width = m_ScreenWidth + (s_PixelOffsetX*2);
			vp.Height = m_ScreenHeight + (s_PixelOffsetY*2);

			vp.MinZ = 0;
			vp.MaxZ = 1;
			SetViewport(vp);


			assert(m_pd3dDevice && "Invalid device!");
			HRESULT hRes = m_pd3dDevice->BeginScene();
			if (FAILED(hRes))
			{
				_LOG(MSG_WARNING, "Failed D3D device BeginScene!");
				m_InvalidState = true;
			}
			return SUCCEEDED(hRes);
		}
		else
		{
			_LOG(MSG_WARNING, "Failed D3D device TestCooperativeLevel!");
			switch (hr)
			{
			case D3DERR_DEVICELOST:				{ _LOG(MSG_WARNING, "Device Lost!"); } break;
			case D3DERR_DEVICENOTRESET:			{ _LOG(MSG_WARNING, "Device not Reset!"); } break;
			case D3DERR_DRIVERINTERNALERROR:	{ _LOG(MSG_WARNING, "Driver Internal Error!"); } break;
			default:							{ _LOG(MSG_WARNING, "Unknown!"); } break;
			}
		}
	}
	return false;
}

void	Dx8Graphics::Clear(COLOR c, float Depth, int Stencil , bool ClearRGB , bool ClearDepth, bool ClearStencil)
{
	DWORD Target = D3DCLEAR_TARGET & ClearRGB;

	m_HasStencilBuffer = false;
	m_HasZBuffer = false;

	Target      |= (ClearStencil && m_HasStencilBuffer) ? D3DCLEAR_STENCIL  : 0;
    Target      |= (ClearDepth && m_HasZBuffer) ? D3DCLEAR_ZBUFFER  : 0;

    if (Target) // did we actually find anything to clear ?
    {
		if (m_pForceTexture)
		{
			c = ColorRGBA(0, 0, 0, 255);	// clear to black so we clearly see overlap
		}
        HRESULT hRes = m_pd3dDevice ->Clear( 0, NULL, Target, c, Depth, Stencil);
		assert(SUCCEEDED(hRes) && "Failed to clear Camera");
    }
}


void	Dx8Graphics::EndScene()
{
	assert(m_pd3dDevice && "Invalid device!");

	// render borders for widescreens
	RenderBorders();

	HRESULT hRes = m_pd3dDevice->EndScene();
//    assert(SUCCEEDED(hRes) && "Failed to end scene ");

	// only time to flush backbuffer
	FlushScreenshot();
	m_FrameID++;
}

bool Dx8Graphics::Present()
{
	assert(m_pd3dDevice && "Invalid device!");
	HRESULT hRes = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
	if (hRes == D3DERR_DEVICELOST)
	{
		Sleep(100);
		// clear any crap the driver may be holding onto
		m_pd3dDevice->Reset(&m_d3dpp);
	}
//    assert(SUCCEEDED(hRes) && "Failed to show Camera");
    return true;
}

void	Dx8Graphics::SetFilter2D(bool Filter)
{
	if (m_Filter2D == Filter)
		return;
	LPDIRECT3DDEVICE8 pDevice = m_pd3dDevice;
	Graphics::SetFilter2D(Filter);

	/*	if (m_Filter2D)
	{
		pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
		pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
		pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR );
	} else
	{
	    pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
		pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
		pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT );
	}*/

	if (m_Filter2D)
	{
		pDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
		pDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
	} else
	{
		pDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT);
		pDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT);
	}
}

void	Dx8Graphics::Start2D()
{
	assert(m_pd3dDevice && "Invalid device!");
	LPDIRECT3DDEVICE8 pDevice = m_pd3dDevice;

	// build a state block out of this?

    pDevice->SetRenderState( D3DRS_WRAP0, 0 );
	pDevice->SetRenderState( D3DRS_WRAP1, 0 );
	pDevice->SetRenderState( D3DRS_WRAP2, 0 );
	pDevice->SetRenderState( D3DRS_WRAP3, 0 );

	pDevice->SetRenderState( D3DRS_LIGHTING,            FALSE);		
	pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,    TRUE );
    pDevice->SetRenderState( D3DRS_SRCBLEND,            D3DBLEND_SRCALPHA );
    pDevice->SetRenderState( D3DRS_DESTBLEND,           D3DBLEND_INVSRCALPHA );
    pDevice->SetRenderState( D3DRS_ALPHATESTENABLE,     TRUE );
    pDevice->SetRenderState( D3DRS_ALPHAREF,            0x02 );
    pDevice->SetRenderState( D3DRS_ALPHAFUNC,           D3DCMP_GREATER );
    pDevice->SetRenderState( D3DRS_FILLMODE,            D3DFILL_SOLID );
    pDevice->SetRenderState( D3DRS_CULLMODE,            D3DCULL_CCW );

	pDevice->SetRenderState( D3DRS_ZENABLE,             FALSE);
	pDevice->SetRenderState( D3DRS_ZVISIBLE,			FALSE);
    pDevice->SetRenderState( D3DRS_ZWRITEENABLE,        FALSE);
    pDevice->SetRenderState( D3DRS_STENCILENABLE,       FALSE );
    pDevice->SetRenderState( D3DRS_CLIPPING,            FALSE );
    pDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,     FALSE );
    pDevice->SetRenderState( D3DRS_VERTEXBLEND,         FALSE );
    pDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
    pDevice->SetRenderState( D3DRS_FOGENABLE,           FALSE );



/*	pDevice->SetSamplerState(0, D3DSAMP_BORDERCOLOR, 0x00);
	pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
	pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
//	pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER );
//	pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER );
*/
	pDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
    pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    pDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
    pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
    pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
    pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
    pDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
    pDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
    pDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
	pDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE ); 

	pDevice->SetTexture(0, NULL);
	pDevice->SetTexture(1, NULL);

	//resetting current textures
	m_pCurTexture[0] = NULL;
	m_pCurTexture[1] = NULL;

	//resetting current render states
	for (int i = 0; i < Graphics::RENDER_STATE_C; i++)
		m_CurRenderStates[i] = 0xffffffff;

	for (int i = 0; i < Graphics::STAGE_TYPE_COUNT; i++)
	{
		m_CurTextureStates[0][i] = Graphics::BLEND_OP_COUNT;
		m_CurTextureStates[1][i] = Graphics::BLEND_OP_COUNT;
	}



	SetFilter2D(false);	
	SetFilter2D(true);	

	m_pd3dDevice->SetVertexShader(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);

}

void	Dx8Graphics::Start3D()
{
	LPDIRECT3DDEVICE8 pDevice = m_pd3dDevice;
	pDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
    pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    pDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
    pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
    pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );

/*	pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
	pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP );*/
    pDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
	pDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE ); 
}

bool	Dx8Graphics::MapPrimitiveToDX(PRIMITIVE_TYPE Type, unsigned int VertC, D3DPRIMITIVETYPE& pt, unsigned int& PrimitiveC)
{
	switch (Type)
	{
		case PT_POINT_LIST:
			pt = D3DPT_POINTLIST;
			PrimitiveC = VertC;
		break;
		case PT_LINE_LIST:
			pt = D3DPT_LINELIST;
			PrimitiveC = VertC/2;
		break;
		case PT_LINE_STRIP:
			pt = D3DPT_LINESTRIP;
			PrimitiveC = VertC-1;
		break;
		case PT_TRI_STRIP:
			pt = D3DPT_TRIANGLESTRIP;
			PrimitiveC = VertC-2;
		break;
		case PT_TRI_FAN:
			pt = D3DPT_TRIANGLEFAN;
			PrimitiveC = VertC-1;
		break;
		case PT_TRI_LIST:	// default case
		default:
			pt = D3DPT_TRIANGLELIST;
			PrimitiveC = VertC/3;
		break;
	}

// do some common debug calculations here
	m_PolygonC+=PrimitiveC;
	m_BatchC++;
	if (m_pForceTexture)
	{
		m_pForceTexture->SetTextureStage(0);
	}

	return true;
}

DX8VertexBuffer*	Dx8Graphics::GetTempVB(int VertC)
{
	if (m_VBSets.empty())
	{
		// lazy generation
		m_VBSets.push_back(new DX8VBSet(30, 32, sizeof(Vertex2D), D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1));
		m_VBSets.push_back(new DX8VBSet(10, 128, sizeof(Vertex2D), D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1));
		m_VBSets.push_back(new DX8VBSet(5,  1024, sizeof(Vertex2D), D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1));
		m_VBSets.push_back(new DX8VBSet(2,  1024 * 64, sizeof(Vertex2D), D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1));
	}
	for (unsigned int i=0; i<m_VBSets.size(); i++)
	{
		if (m_VBSets[i]->CanFit(VertC)) return (DX8VertexBuffer*)m_VBSets[i]->GetBuffer();
	}
	return NULL;
}

DX8IndexBuffer*	Dx8Graphics::GetTempIB(int IndexC)
{
	if (m_IBSets.empty())
	{
		// lazy generation
		m_IBSets.push_back(new DX8IBSet(30, 32));
		m_IBSets.push_back(new DX8IBSet(5, 1024));
		m_IBSets.push_back(new DX8IBSet(5, 1024*64));
	}
	for (unsigned int i=0; i<m_IBSets.size(); i++)
	{
		if (m_IBSets[i]->CanFit(IndexC)) return (DX8IndexBuffer*)m_IBSets[i]->GetBuffer();
	}
	return NULL;
}


void	Dx8Graphics::DrawVertex2D(Vertex2D*	VertA, unsigned int VertC, PRIMITIVE_TYPE Type )
{
	if (VertC == 0)	return;	// no vertices
	assert(m_pd3dDevice && "Invalid device!");
	
	unsigned int		PrimitiveC;
	D3DPRIMITIVETYPE	pt;

	MapPrimitiveToDX(Type, VertC, pt, PrimitiveC);

///	m_pd3dDevice->SetVertexShader(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
	HRESULT hRes = S_OK;
/*	hRes = m_pd3dDevice->DrawPrimitiveUP(pt, PrimitiveC, VertA, sizeof(Vertex2D));

	m_pd3dDevice->SetTexture(0, NULL);*/

	DX8VertexBuffer*	pBuffer = GetTempVB(VertC);
	if (pBuffer)
	{
		pBuffer->Load(VertA, VertC);
		hRes = m_pd3dDevice->SetStreamSource( 0, pBuffer->GetBuffer(), sizeof(Vertex2D) );
		hRes = m_pd3dDevice->DrawPrimitive(pt, 0, PrimitiveC);
		if (FAILED(hRes))
		{
			_LOG(MSG_ERROR, "Unable to draw array : DX Error: " << GetDXError(hRes));
		}
		//m_pd3dDevice->SetTexture(0, NULL);
	}
}

void	Dx8Graphics::DrawIndexVertex2D(Vertex2D*	VertA, unsigned int VertC, unsigned short* IndexA, unsigned int IndexC, PRIMITIVE_TYPE Type)
{
	unsigned int		PrimitiveC;
	D3DPRIMITIVETYPE	pt;
	MapPrimitiveToDX(Type, IndexC, pt, PrimitiveC);


/*	GLenum GLMode;
	unsigned int PrimitiveC = 0;
	MapPrimitiveToOGL(Type,GLMode,IndexC,PrimitiveC);
	glBegin( GLMode);
	for(unsigned int i =0 ; i < IndexC; i++)
	{
		Vertex2D* pVert = &VertA[IndexA[i]]; 
		glTexCoord2f(pVert->u, -pVert->v); 
		glColor3ubv(&pVert->color); 
		glVertex2f(pVert->x/m_ScreenWidth, 1 - (pVert->y/m_ScreenHeight)); 
	}
	glEnd();
*/



	DX8VertexBuffer*	pVB = GetTempVB(VertC);
	DX8IndexBuffer*	pIB = GetTempIB(IndexC);
	if (pVB && pIB)
	{
		pVB->Load(VertA, VertC);
		pIB->Load(IndexA, IndexC);
		m_pd3dDevice->SetStreamSource( 0, pVB->GetBuffer(), sizeof(Vertex2D) );
		m_pd3dDevice->SetIndices(pIB->GetBuffer(), 0);
		HRESULT hRes = m_pd3dDevice->DrawIndexedPrimitive(pt, 0, VertC, 0, PrimitiveC);
		if (FAILED(hRes))
		{
			_LOG(MSG_ERROR, "Unable to draw array : DX Error: " << GetDXError(hRes));
		}
	}
	//m_pd3dDevice->SetTexture(0, NULL);

}

void	Dx8Graphics::DrawFatIndexVertex2D(FatVertex2D*	VertA, unsigned int VertC, unsigned short* IndexA, unsigned int IndexC, PRIMITIVE_TYPE Type)
{
	unsigned int		PrimitiveC;
	D3DPRIMITIVETYPE	pt;
	MapPrimitiveToDX(Type, IndexC, pt, PrimitiveC);


	LPDIRECT3DDEVICE8 pDevice = m_pd3dDevice;
	m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_BLENDCURRENTALPHA );
    m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
    m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );
    m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG2 );
    m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
    m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);

	m_pd3dDevice->SetVertexShader(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX2);
	HRESULT hRes = m_pd3dDevice->DrawIndexedPrimitiveUP(pt, 0, VertC, PrimitiveC, 
						IndexA, D3DFMT_INDEX16,	VertA, sizeof(FatVertex2D));
	if (FAILED(hRes))
	{
		_LOG(MSG_ERROR, "Unable to draw array : DX Error: " << GetDXError(hRes));
	}

	m_pd3dDevice->SetTexture(0, NULL);
	m_pCurTexture[0] = NULL;
    m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
	m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE ); 
}


void	Dx8Graphics::DrawVertex3D(Vertex3D*	VertA, unsigned int VertC, PRIMITIVE_TYPE Type )
{
	if (VertC == 0)	return;	// no vertices
	assert(m_pd3dDevice && "Invalid device!");
	
	unsigned int		PrimitiveC;
	D3DPRIMITIVETYPE	pt;

	MapPrimitiveToDX(Type, VertC, pt, PrimitiveC);

	m_pd3dDevice->SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1);
	HRESULT hRes = m_pd3dDevice->DrawPrimitiveUP(pt, PrimitiveC, VertA, sizeof(Vertex3D));
	if (FAILED(hRes))
	{
		_LOG(MSG_ERROR, "Unable to draw array : DX Error: " << GetDXError(hRes));
	}
}

void	Dx8Graphics::DrawIndexVertex3D(Vertex3D*	VertA, unsigned int VertC, unsigned short* IndexA, unsigned int IndexC, PRIMITIVE_TYPE Type)
{
	if (VertC == 0 || IndexC == 0)	return;	// no vertices

	assert(m_pd3dDevice && "Invalid device!");
	
	unsigned int		PrimitiveC;
	D3DPRIMITIVETYPE	pt;
	MapPrimitiveToDX(Type, IndexC, pt, PrimitiveC);

	m_pd3dDevice->SetVertexShader(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1);

	HRESULT hRes = m_pd3dDevice->DrawIndexedPrimitiveUP(pt, 0, VertC, PrimitiveC, 
						IndexA, D3DFMT_INDEX16,	VertA, sizeof(Vertex3D));
	if (FAILED(hRes))
	{
		_LOG(MSG_ERROR, "Unable to draw array : DX Error: " << GetDXError(hRes));
	}
}



static std::string		YesNo(unsigned int Val)
{
	if (Val) return "Yes";
	return "No";
}

static unsigned int	BytesToMB(SIZE_T SizeInByte)
{
	return (unsigned int)(((SizeInByte+(16*1024*1024-1)) & ~(16*1024*1024-1) ) >> 20);
}
static std::string		OS_Version(unsigned int Major, unsigned int Minor, unsigned int Suite)
{
	if (Major == 3)
	{
		return "Windows NT 3.51";
	} else
	if (Major == 4)
	{
		switch (Minor)
		{
			case	0:	return "Windows 95";
			case	10:	return "Windows 98";
			case	90:	return "Windows Me";
			default:	return "Unknown OS";
		}
	} else
	if (Major == 5)
	{
		switch (Minor)
		{
			case	0:	return "Windows 2000";
			case	1:	
			{
				switch (Suite)
				{
					case VER_SUITE_ENTERPRISE: return "Windows .NET Enterprise Server";
					case VER_SUITE_PERSONAL: return "Windows XP Home Edition";
					default:				return "Windows XP";
				}
			}
			default:	return "Unknown OS";
		}
	} else
	if (Major == 6)
	{
		return "Windows Vista";
	}
	return "Unknown OS";
}

static bool	g_Has32Bit = false;
void	Dx8Graphics::EnumerateDisplayModes(D3DFORMAT Format, unsigned int MinWidth, unsigned int MinHeight, unsigned int MinRefresh)
{
	unsigned int	ModeC = m_pD3D->GetAdapterModeCount(m_DeviceID);
	for (unsigned int i=0; i<ModeC; i++)
	{
		D3DDISPLAYMODE displayMode;
		m_pD3D->EnumAdapterModes( m_DeviceID,  i, &displayMode );

		if (displayMode.Height >= MinHeight &&
			displayMode.Width >= MinWidth &&
			displayMode.RefreshRate >= MinRefresh)
		{
			std::string	FormatStr;
			unsigned int Depth  = 32;
			switch (displayMode.Format)
			{
				case D3DFMT_A1R5G5B5:			
					Depth = 16;
					FormatStr = "D3DFMT_A1R5G5B5"; 
					break;
				case D3DFMT_A8R8G8B8:			
					Depth = 32;
					FormatStr = "D3DFMT_A8R8G8B8"; 
					break;
				case D3DFMT_R5G6B5:				
					Depth = 16;
					FormatStr = "D3DFMT_R5G6B5"; 
					break;
				case D3DFMT_X1R5G5B5:			
					Depth = 16;
					FormatStr = "D3DFMT_X1R5G5B5"; 
					break;
				case D3DFMT_X8R8G8B8:			
					Depth = 32;
					FormatStr = "D3DFMT_X8R8G8B8"; 
					break;
			}

			_LOG(MSG_INIT, " - ["	<< displayMode.Width << " x " << displayMode.Height << " x " << Depth
									<< "] @ " << displayMode.RefreshRate << "(" << FormatStr << ")");

			if (Depth==32)
			{
				g_Has32Bit=true;
			}
			m_Modes.push_back(displayMode);
		}
	}
}

void    Dx8Graphics::InitCaps()
{
	int	AdapterC = m_pD3D->GetAdapterCount();
	_LOG(MSG_INIT, "System has " << AdapterC << " devices");
	int		ValidAdapter = -1;
	for (int i=0; i<AdapterC; i++)
	{
		D3DADAPTER_IDENTIFIER8	Ident;
		m_pD3D->GetAdapterIdentifier(i, 0,&Ident);

		_LOG(MSG_INIT, " Adapter : " << i);
		_LOG(MSG_INIT, " - Device Name		: " << Ident.DeviceId);
		_LOG(MSG_INIT, " - Description		: " << Ident.Description);
		_LOG(MSG_INIT, " - Driver			: " << Ident.Driver);
		_LOG(MSG_INIT, " - Driver Version	: [" << Ident.DriverVersion.HighPart << "," << Ident.DriverVersion.LowPart << "]");
		_LOG(MSG_INIT, " - Vendor Info		: [" << Ident.VendorId << ", " << Ident.DeviceId );

		HRESULT	Supported = m_pD3D->CheckDeviceType(i,	D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DFMT_UNKNOWN, true);
		if (SUCCEEDED(Supported))
		{
			if (ValidAdapter < 0)
				ValidAdapter = i;
			_LOG(MSG_INIT, " - Device supports HAL");
		}
	}
	
	if (ValidAdapter >= 0)	m_DeviceID = ValidAdapter;

	HRESULT hRes = m_pD3D->GetDeviceCaps(
							m_DeviceID,			// Default adapter
							D3DDEVTYPE_HAL,		// we're interested in the HW card
							&m_d3d8Caps);		// Fill'er'up
	if (FAILED(hRes))
	{
        _LOG(MSG_ERROR, "Unable to retrieve graphics card capabilities");
        _LOG(MSG_ERROR, "DX Error: " << GetDXError(hRes));

		m_DeviceID = 1;
		HRESULT hRes = m_pD3D->GetDeviceCaps(	
								m_DeviceID,			// Default adapter
								D3DDEVTYPE_HAL,		// we're interested in the HW card
								&m_d3d8Caps);		// Fill'er'up
		if (FAILED(hRes))
		{
			_LOG(MSG_ERROR, "Can't find a valid adaptor!");
			_LOG(MSG_ERROR, "DX Error: " << GetDXError(hRes));
			MessageBox(NULL, "There was an error creating the 3D window. Now exiting.", "Unable to create Game Window!", MB_OK);
			exit(0);
		}
		return;
	}

	std::string	DXClass = "DX8";
	if (!(m_d3d8Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT))	// no hardware T&L
	{
		m_GraphicsClass = GRAPHICS_CLASS_DX6;
		DXClass = "DX6";
	} else
	if (!(m_d3d8Caps.PixelShaderVersion >= D3DPS_VERSION( 1, 1 )))	// no pixel shaders, so not dx8 class
	{
		m_GraphicsClass = GRAPHICS_CLASS_DX7;
		DXClass = "DX7";
	} else
	if (!(m_d3d8Caps.PixelShaderVersion >= D3DPS_VERSION( 2,0 )))	// no 2.0 pixel shaders, so not dx8 clas
	{
		m_GraphicsClass = GRAPHICS_CLASS_DX8;
		DXClass = "DX8";
	} else
		m_GraphicsClass = GRAPHICS_CLASS_DX8;

	/// output information about device
	util::Logger::Instance().SetVerbose(false);

	_LOG(MSG_INIT, "------------------------------------------");
	_LOG(MSG_INIT, "SYSTEM INFORMATION");
	_LOG(MSG_INIT, "------------------------------------------");
	_LOG(MSG_INIT, "Device info");
	_LOG(MSG_INIT, " - supports HW T&L : " <<YesNo( m_d3d8Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT));
	_LOG(MSG_INIT, " - supports HW Rasterizing : " << YesNo(m_d3d8Caps.DevCaps & D3DDEVCAPS_HWRASTERIZATION));
	_LOG(MSG_INIT, " - consider graphics card " << DXClass << " class.");

	_LOG(MSG_INIT, "Texture info");
	_LOG(MSG_INIT, " - Max texture size : ["	<< m_d3d8Caps.MaxTextureWidth << "x" << m_d3d8Caps.MaxTextureHeight << "]");
	_LOG(MSG_INIT, " - Max texture aspect: "	<< m_d3d8Caps.MaxTextureAspectRatio);
	_LOG(MSG_INIT, " - supports Alpha : "		<< YesNo(m_d3d8Caps.TextureCaps & D3DPTEXTURECAPS_ALPHA));
	_LOG(MSG_INIT, " - supports Cubemaps : "	<< YesNo(m_d3d8Caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP));
	_LOG(MSG_INIT, " - supports Cubemaps only Pow2 : "	<< YesNo(m_d3d8Caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2));
	_LOG(MSG_INIT, " - supports Mipmaps : "				<< YesNo(m_d3d8Caps.TextureCaps & D3DPTEXTURECAPS_MIPMAP));
	_LOG(MSG_INIT, " - supports Conditional non-Pow2 : "<< YesNo(m_d3d8Caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL));
	_LOG(MSG_INIT, " - supports Pow2 textures ONLY : "	<< YesNo(!(m_d3d8Caps.TextureCaps & D3DPTEXTURECAPS_POW2)));
	_LOG(MSG_INIT, " - supports only square textures : "<< YesNo(m_d3d8Caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY));

	_LOG(MSG_INIT, "Texture Adress info");
	_LOG(MSG_INIT, " - supports Clamping : "					<< YesNo(m_d3d8Caps.TextureAddressCaps & D3DPTADDRESSCAPS_CLAMP));
	_LOG(MSG_INIT, " - supports Wrapping : "					<< YesNo(m_d3d8Caps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP));

	_LOG(MSG_INIT, "Vertex & Pixel Shaders");
	if (m_d3d8Caps.VertexShaderVersion >= D3DVS_VERSION( 1,1 ))
	{
		_LOG(MSG_INIT, " - Vertex Shader 1.1 supported");
	}
	else
	{
		_LOG(MSG_INIT, " - No Vertex Shader supported");
	}
	if (m_d3d8Caps.VertexShaderVersion >= D3DVS_VERSION( 2,0 ))
		_LOG(MSG_INIT, " - Vertex Shader 2.0 supported");
	if (m_d3d8Caps.VertexShaderVersion >= D3DVS_VERSION( 3,0 ))
		_LOG(MSG_INIT, " - Vertex Shader 3.0 supported");

	if (m_d3d8Caps.PixelShaderVersion >= D3DPS_VERSION( 1,1 ))
	{
		_LOG(MSG_INIT, " - Pixel Shader 1.1 supported");
	}	else
	{
		_LOG(MSG_INIT, " - No Pixel Shaders supported");
	}

	if (m_d3d8Caps.PixelShaderVersion >= D3DPS_VERSION( 1,2 ))
		_LOG(MSG_INIT, " - Pixel Shader 1.2 supported");
	if (m_d3d8Caps.PixelShaderVersion >= D3DPS_VERSION( 1,3 ))
		_LOG(MSG_INIT, " - Pixel Shader 1.3 supported");
	if (m_d3d8Caps.PixelShaderVersion >= D3DPS_VERSION( 1,4 ))
		_LOG(MSG_INIT, " - Pixel Shader 1.4 supported");
	if (m_d3d8Caps.PixelShaderVersion >= D3DPS_VERSION( 2,0 ))
		_LOG(MSG_INIT, " - Pixel Shader 2.0 supported");
	if (m_d3d8Caps.PixelShaderVersion >= D3DPS_VERSION( 3,0 ))
		_LOG(MSG_INIT, " - Pixel Shader 3.0 supported");
	
	_LOG(MSG_INIT, "Device info");
//	_LOG(MSG_INIT, " - supports mip-map autogen : "		<< YesNo(m_d3d8Caps.Caps2& D3DCAPS2_CANAUTOGENMIPMAP));
	_LOG(MSG_INIT, " - supports managed resources : "	<< YesNo(m_d3d8Caps.Caps2& D3DCAPS2_CANMANAGERESOURCE));
	_LOG(MSG_INIT, " - supports dynamic textures : "	<< YesNo(m_d3d8Caps.Caps2& D3DCAPS2_DYNAMICTEXTURES));
//	_LOG(MSG_INIT, " - supports copy [SYS->VRAM] : "	<< YesNo(m_d3d8Caps.Caps3& D3DCAPS3_COPY_TO_VIDMEM));
//	_LOG(MSG_INIT, " - supports copy [VRAM->SYS] :"		<< YesNo(m_d3d8Caps.Caps3& D3DCAPS3_COPY_TO_SYSTEMMEM));
//	_LOG(MSG_INIT, " - supports strechblit		 :"		<< YesNo(m_d3d8Caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES ));



	D3DADAPTER_IDENTIFIER8	AdapterInfo;
	hRes = m_pD3D->GetAdapterIdentifier(m_DeviceID, 0, &AdapterInfo);
	if (!FAILED(hRes))
	{
		_LOG(MSG_INIT, "Adapter info");
		_LOG(MSG_INIT, " - Device		: " << AdapterInfo.Description);
		_LOG(MSG_INIT, " - Driver		: " << AdapterInfo.Driver << 
											" [ " << AdapterInfo.DriverVersion.LowPart << 
											", " << AdapterInfo.DriverVersion.HighPart << " ]");
		_LOG(MSG_INIT, " - Vendor ID	: " << AdapterInfo.VendorId);
		_LOG(MSG_INIT, " - Device ID	: " << AdapterInfo.DeviceId);

		char		Buffer[256];
		sprintf(Buffer, "[%s]", AdapterInfo.Description, AdapterInfo.Driver, AdapterInfo.DriverVersion.LowPart, AdapterInfo.DriverVersion.HighPart);
		m_GraphicsInfo = Buffer;
	}
	
	// system info
	SYSTEM_INFO SysInfo;
	GetSystemInfo(&SysInfo); 
	_LOG(MSG_INIT, "System Info");
//	_LOG(MSG_INIT, " - Clockspeed : " << TIMER().GetClockSpeed() << " mhz");
	_LOG(MSG_INIT, " - CPU Count  : "  << SysInfo.dwNumberOfProcessors);
	_LOG(MSG_INIT, " - CPU Type   : "  << SysInfo.dwProcessorType);

	// version info
	OSVERSIONINFOEX  OSInfo;
	memset(&OSInfo, 0, sizeof(OSInfo));
	OSInfo.dwOSVersionInfoSize = sizeof(OSInfo);
	unsigned int Success = GetVersionEx((LPOSVERSIONINFO)&OSInfo);
	
	_LOG(MSG_INIT, " - OS Version : " << OS_Version(OSInfo.dwMajorVersion, OSInfo.dwMinorVersion, OSInfo.wSuiteMask));

	unsigned int	Network_Enabled = GetSystemMetrics(SM_NETWORK);
	_LOG(MSG_INIT, " - Network Enabled : " << YesNo(Network_Enabled));


	// ram
    MEMORYSTATUS ms;
    GlobalMemoryStatus( &ms );
	_LOG(MSG_INIT, " - Total Physical RAM		: " << BytesToMB(ms.dwTotalPhys) << " MB");
	_LOG(MSG_INIT, " - Free Physical RAM		: " << BytesToMB(ms.dwAvailPhys) << " MB");
	_LOG(MSG_INIT, " - Total Pagefile			: " << BytesToMB(ms.dwTotalPageFile) << " MB");
	_LOG(MSG_INIT, " - Available Pagefile		: " << BytesToMB(ms.dwAvailPageFile) << " MB");
	_LOG(MSG_INIT, " - Total Virtual RAM		: " << BytesToMB(ms.dwTotalVirtual) << " MB");
	_LOG(MSG_INIT, " - Available Virtual RAM	: " << BytesToMB(ms.dwAvailVirtual) << " MB");

	// system metrics

	_LOG(MSG_INIT, "Viable Display Modes");

	char	Buffer[256];
	sprintf(Buffer, "[%s][Total:%i Free:%i Virtual:%i][CPU:%i x %i ]", 
		OS_Version(OSInfo.dwMajorVersion, OSInfo.dwMinorVersion, OSInfo.wSuiteMask).c_str(),	// OS
		BytesToMB(ms.dwTotalPhys), BytesToMB(ms.dwAvailPhys), BytesToMB(ms.dwAvailVirtual),	//RAM
		SysInfo.dwProcessorType, SysInfo.dwNumberOfProcessors);
	m_SystemInfo = Buffer;

	if (OSInfo.dwMajorVersion== 6)	m_BugList[BUG_VISTA_ALTTAB] = true;	// might also be triggered if the current resolution is

	g_Has32Bit = false;
	m_Modes.resize(0);
	EnumerateDisplayModes(D3DFMT_A1R5G5B5, 640, 480, 60);
	EnumerateDisplayModes(D3DFMT_R5G6B5, 640, 480, 60);
	EnumerateDisplayModes(D3DFMT_X1R5G5B5, 640, 480, 60);
	EnumerateDisplayModes(D3DFMT_A8R8G8B8, 640, 480, 60);
	EnumerateDisplayModes(D3DFMT_X8R8G8B8, 640, 480, 60);

	if (!g_Has32Bit)	m_BugList[BUG_16BIT_ONLY] = true;	// might also be triggered if the current resolution is

	DEVMODE device_mode;
	memset(&device_mode, 0, sizeof(DEVMODE));
	device_mode.dmSize = sizeof(DEVMODE);
	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &device_mode);

	int Depth = device_mode.dmBitsPerPel;
	if (Depth==16)
	{
		m_BugList[BUG_16BIT_ONLY] = true;	// might also be triggered if the current resolution is
	}

	// react if the screen-size is less than 800x600 as well?

	util::Logger::Instance().SetVerbose(true);

	/// track bugs
	m_BugList[BUG_SQUARE_TEXTURES] = 
		(m_d3d8Caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) ||
		(m_d3d8Caps.MaxTextureAspectRatio == 1);

}


std::string  Dx8Graphics::GetDXError(HRESULT _Res)
{
	const char*	szErrorText = DXGetErrorString8(_Res);
    if (szErrorText)    // check we didn't get an empty string
        return szErrorText;
    return "no error";
}

AVI*	Dx8Graphics::LoadMovie(const std::string& Name)
{
	Dx8AVI*	pAVI = new Dx8AVI();
	pAVI->Load(Name);
	m_ActiveMovies.push_back(pAVI);
	return pAVI;
}

void	Dx8Graphics::DestroyMovie(AVI* pAVI)
{
	if (pAVI)
	{
		Dx8AVI*	pDXAVI  = (Dx8AVI*)	pAVI;
		for (unsigned int i=0; i<m_ActiveMovies.size(); i++)
		{
			if (m_ActiveMovies[i]==pAVI)
			{
				delete pDXAVI;
				m_ActiveMovies.erase(m_ActiveMovies.begin()+i);
				return;
			}
		}
		assert(0 && "Trying to delete invalid movie!");
	}
}


Image*	Dx8Graphics::LoadImageFromFile(const std::string& Input)
{
	std::string	Format = Input;
	if (Format.empty())
	{
        _LOG(MSG_WARNING, "Trying to load texture, but no file-name given");
		return NULL;
	}
	if (Format.size() < 4)
    {
        _LOG(MSG_WARNING, "Unable to find the file-type of image file " << Format);
        return NULL;
    }

	const char*     File    = Format.c_str();
	size_t          SL      = strlen(File);
	char	        Ext[]   = { tolower(File[SL-3]), 
				    	        tolower(File[SL-2]), 
						        tolower(File[SL-1]), 
						        '\0'};

    if (File[SL-4] != '.')  // all internal file formats are 3 lettered extensions
    {
        _LOG(MSG_WARNING, "Unable to find the file-type of image file " << Format);
        return NULL;
    }
	bool	EnableDDS = (strcmp(Ext, "dds")!=0);	// read this from file in addition?

	if (EnableDDS)		// do this from a config instead?
	{
		std::string		Test = vfs::VFS::StripExtension(Format) + ".DDS";
		if (vfs::VFS::Instance().FileExists(Test))
		{
			Format = Test;
			strcpy(Ext, "dds");	 //files are just quietly overwritten
		}
	}


    Image* pImg = NULL;

	if (strcmp(Ext, "tga")==0) pImg = new Image(); else
	if (strcmp(Ext, "bmp")==0) pImg = new Image(); else
	if (strcmp(Ext, "jpg")==0) pImg = new Image(); else
	if (strcmp(Ext, "png")==0) pImg = new Image(); else
	if (strcmp(Ext, "dds")==0) pImg = new Image(); else
	if (strcmp(Ext, "ddc")==0) pImg = new Image(); else
	if (strcmp(Ext, "tex")==0) pImg = new Image(); else       // flipping chain
	if (strcmp(Ext, "avi")==0) pImg = new Dx8AVI();		// AVI File

    if (pImg)
    {
        if (!pImg->Load(Format))
        {
            UTIL_SAFE_DELETE(pImg);
        }
    }
    return pImg;
}
Image*	Dx8Graphics::LoadImageFromMemory(unsigned char* pData, unsigned int	Size)
{

    Image* pImg = new Image();
	Dx8Surface*	pSurf = (Dx8Surface*)Dx8Surface::CreateImage();
	pSurf->FromMemory(pData, Size);
	pSurf->InitTexture(); 
	pImg->SetSurface(pSurf);
	return pImg;
}



Image*	Dx8Graphics::CreateDynamicImage(unsigned short Width, unsigned short Height, unsigned short Depth)
{
	Image* pImg = new Dx8DynamicImage(Width, Height, Depth);
	pImg->Load("");
	return pImg;	
}

Image*	Dx8Graphics::CreateComposite(int	width, int height, int depth, const std::vector<ImageLayer>& Layers)
{
	assert(depth == 32);	// only deal in 32 bit images for now. No translation.

	// create the image
    LPDIRECT3DTEXTURE8		pImage;					
	HRESULT  hRes = m_pd3dDevice->CreateTexture(  width, height, 0,
												0, 
												D3DFMT_A8R8G8B8,
												D3DPOOL_MANAGED, 
												&pImage);
	assert(SUCCEEDED(hRes));

	D3DLOCKED_RECT d3dlr;
	pImage->LockRect( 0, &d3dlr, 0, 0 );
		memset(d3dlr.pBits, 0, height * d3dlr.Pitch);

		// for each image in the set
		for (unsigned int i=0; i<Layers.size(); i++)
		{
			const ImageLayer& Layer = Layers[i];
			if (Layer.pImage && Layer.pImage->GetSurface())
			{
				Dx8Surface* pSurf = (Dx8Surface*)Layer.pImage->GetSurface();
				pSurf->CopyOntoSource(&d3dlr, width, height, Layer.x, Layer.y);
			}
		}
	pImage->UnlockRect(0);

	Dx8Surface*		pSurf = Dx8Surface::FromTexture(pImage, width, height);
	Image*			pFinalImage = new Image();
	pFinalImage->SetSurface(pSurf);
	return pFinalImage;
}

Font*	Dx8Graphics::CreateTTFFont(const std::string& Name) 
{ 
//	return new Dx8FontX(Name); 
	return new DX8Font(Name); 
};

void	Dx8Graphics::RegisterFormats()
{
	Dx8Surface::RegisterFormats();
}

void	Dx8Graphics::GetBestWideScreenRes(unsigned int& aWidth, unsigned int& aHeight, bool bGetForBackbuffer)
{
	_LOG(MSG_COMMENT, "Detecting Widescreen Res" << (bGetForBackbuffer ? " for backbuffer" : " for display"));
	unsigned long closestDist = 0xFFFF;
	unsigned int TargetW = g_pApp->GetHandler()->ScreenWidth();
	unsigned int TargetH = g_pApp->GetHandler()->ScreenHeight();
	unsigned int OrigW = g_pApp->GetHandler()->GetOrigWidth();
	unsigned int OrigH = g_pApp->GetHandler()->GetOrigHeight();

	//g_pApp->GetHandler()->IsNativeWidescreen() = false;
	g_pApp->GetHandler()->SetIsNativeWideScreen(false);	

	for (int i = 0; i < (int)m_Modes.size(); ++i) {
		unsigned long w = m_Modes[i].Width;
		unsigned long h = m_Modes[i].Height;

		if ((w > OrigW) || (h > OrigH)) continue; // ADRIAN: don't pick a resolution HIGHER than original desktop size

		float aspect = float(w)/float(h);
		if ((aspect > 1.5f) && (w >= TargetW) && (h >= TargetH)) {
			unsigned long diff = h-TargetH;
			if (diff == 0 ) //&& (fabs(aspect - g_DesktopAspectRatio) < 0.01f))
			{
				// perfect match!
				g_pApp->GetHandler()->SetIsNativeWideScreen(true);
				aWidth = w;
				aHeight = h;
				_LOG(MSG_COMMENT, "Found Native Widescreen Res : " << aWidth << "x" << aHeight);
				return;
			}
			else if (diff < closestDist)
			{
				aWidth = w;
				aHeight = h;
				closestDist = diff;
				_LOG(MSG_COMMENT, "Found possible Widescreen Res : " << aWidth << "x" << aHeight);
			}
		}
	}
	
	if (bGetForBackbuffer || (closestDist == 0xFFFF))
	{
		if (bGetForBackbuffer)
		{
			aHeight = TargetH;
			//this should return a widesreen aspect ratio
			float	DesktopAspect = (float)g_pApp->GetHandler()->GetOrigWidth() / (float)g_pApp->GetHandler()->GetOrigHeight();
			aWidth = (unsigned int)(DesktopAspect * (float)TargetH);
			// ADRIAN: round down to nearest multiple of 8?
			aWidth -= (aWidth % 8);
		}
		else
		{
			// just default to current screen res
			aWidth = GetSystemMetrics(SM_CXSCREEN);
			aHeight = GetSystemMetrics(SM_CYSCREEN);
		}
	}


	_LOG(MSG_COMMENT, "Best Widescreen Res : " << aWidth << "x" << aHeight);
}


void	Dx8Graphics::Flush()
{
	m_pd3dDevice->SetTexture(0, NULL);
	m_pd3dDevice->SetTexture(1, NULL);
	Graphics::Flush();
	FlushBuffers();
}

void	Dx8Graphics::Recreate()
{
	Graphics::Recreate();

}
